/*---------------------------------------------------------------------------------

	by GugloPWN

---------------------------------------------------------------------------------*/

#include "player.h"

void player::getdefaultplayer()
{


	mapx = 2;
	mapy = 1;

	m = new map();

	x = 10;
	y = 10;
	z = 10;
	vx = 0;
	vy = 0;
	vz = 0;
	dir = 0;
	
	camx = 0;
	camy = 0;
	camz = 15;
	
	animation = 0;
	
	paint = 10;
	score = 0;
	charmodel = 0;
	isground = false;
	isgrindrail = false;
	isgrindwall = false;
	isjump = false;
	maxspeed = 0.16;
	maxcamdist = 4;
	mincamdist = 1.7;
	
	currail = -1;
	pastrail = -1;
	
	
	//Temporary stuff
	zoom=1.0f;
	scale=10000;
	frame=0;
	change=0;
}
	
void player::loadcharmodel()
{
	printf("Loading Character Texture\n");
	glGenTextures(1, Texture);
	LoadModelTexture("test.bmp",Texture,TexturePal,&textsize) ;
	printf("Loading Character Model\n");
	LoadMD2Model("test.md2",textsize,1,Model,ModelEnable);
	printf("Done.\n");
}
	
void player::updateplayer()
{
/*	//Temporary orthagonal controls
	if(vx > 0){vx -= 0.004;}
	else if(vx < 0){vx += 0.004;}
	if(vy > 0){vy -= 0.004;}
	else if(vy < 0){vy += 0.004;}
	
	if ((keysHeld() & KEY_UP)) vy +=0.01;
	if ((keysHeld() & KEY_DOWN)) vy -=0.01;
	if ((keysHeld() & KEY_LEFT)) vx -=0.01;
	if ((keysHeld() & KEY_RIGHT)) vx +=0.01;
	
	x += vx;
	y += vy;
*/

	//Controls based on camera position
	//Controls for on the ground
	float control;
	
	
	if(isground == true) control = 0.005;
	if(isground == false)
	{ 
		if((isgrindwall == true) || (isgrindrail == true))
		{
			control = 0.0;
		}
		else
		{
			control = 0.0025;
		}
	}
	
	float delx = camx-x;
	float dely = camy-y;
	float camdist = sqrt(delx*delx + dely*dely);
	float ratio = 1/camdist;
	
	if(isground == true)
	{
		if(vx > 0){vx -= 0.002;}
		else if(vx < 0){vx += 0.002;}
		if(vy > 0){vy -= 0.002;}
		else if(vy < 0){vy += 0.002;}
		
		if((-0.001 < vx) && (vx < 0.001)) vx = 0;
		if((-0.001 < vy) && (vy < 0.001)) vy = 0;
	}

	if ((keysHeld() & KEY_UP))
	{ 
		vy -= control*dely*ratio;
		vx -= control*delx*ratio;
	}
	if ((keysHeld() & KEY_DOWN))
	{ 
		vy += control*dely*ratio;
		vx += control*delx*ratio;
	}
	if ((keysHeld() & KEY_LEFT))
	{
		vy -= control*delx*ratio;
		vx += control*dely*ratio;
	}
	if ((keysHeld() & KEY_RIGHT))
	{
		vy += control*delx*ratio;
		vx -= control*dely*ratio;
	}


	//camdist is used as the speed magnitude here to use fewer variables
	camdist = sqrt(vx*vx + vy*vy);
	if(camdist > maxspeed)
	{
		vx = vx*maxspeed/camdist;
		vy = vy*maxspeed/camdist;
	}
	
	//isgrindwall = false;
		
	//Collison with tiles
	bool ishitx = checkxcol();
	bool ishity = checkycol();

	if(ishitx == true)
	{
		if((vz < 0) && (fabs(vy) > 0.08)) isgrindwall = true;
	}
	if(ishity == true)
	{
		if((vz < 0) && (fabs(vx) > 0.08)) isgrindwall = true;
	}
	
	
	handlez();
	if(isgrindrail == false) 
	{
		checkrailcol();
	}
	else
	{
		isgrindrail = closerailcol(m->getblockrail(mapx,mapy,currail), currail);
	}
	
	x += vx;
	y += vy;
	z += vz;
	
	if(x > 20) 
	{
		mapx++;
		x -= 20;
		camx -= 20;
	}
	else if(x < 0) 
	{
		mapx--;
		x += 20;
		camx += 20;
	}
	if(y > 20) 
	{
		mapy++;
		y -= 20;
		camy -= 20;
	}
	else if(y < 0) 
	{
		mapy--;
		y += 20;
		camy += 20;
	}
	
	//update direction facing
	if((vx != 0) && (vy != 0))
	{
		if(vx > 0) dir = (int)(atan(vy/vx)*180/3.14);
		if(vx < 0) dir = 180+(int)(atan(vy/vx)*180/3.14);
	}
	
	setframe();
	
	//Print position and velocity to console
	printf("\npos: %.4f %.4f %.4f\n", x,y,z);
	printf("vel: %.2f %.2f %.2f\n", vx,vy,vz);
	printf("map: %d %d\n", mapx,mapy);
	printf("animation frame: %d", frame);
}

bool player::checkrailcol()
{
	//Room for optimization here if the game laggs when their are lots of rails
	int i;
	bool maybe;
	rail r;
	

	for(i=0;i<16;i++)
	{
			r = m->getblockrail(mapx,mapy,i);
			if(r.a.x != 21)
			{
				if(r.a.z >= r.b.z)
				{
					if((r.b.z < (z+8)) && (r.a.z > (z)))
					{
						maybe = closerailcol(r,i);
						if(maybe == true) return true;
					}
				}
				else
				{
					if((r.a.z < (z+8)) && (r.b.z > (z)))
					{
						maybe = closerailcol(r,i);
						if(maybe == true) return true;
					}
				}
			}
	}


	currail= -1; 
	pastrail = -1;
	return false;

}

bool player::closerailcol(rail r, int i)
{
	//calculate intersection point the first equation is in 3d which strangly isnt what I want.
	//float u = (((x+vx) - (float)r.a.x)*(float)(r.b.x-r.a.x) + ((y+vy) - (float)r.a.y)*(float)(r.b.y-r.a.y) + ((z+vz) - (float)r.a.z)*(float)(r.b.z-r.a.z))/(float)((r.a.x-r.b.x)*(r.a.x-r.b.x)+(r.a.y-r.b.y)*(r.a.y-r.b.y)+(r.a.z-r.b.z)*(r.a.z-r.b.z));
	float u = (((x+vx) - (float)r.a.x)*(float)(r.b.x-r.a.x) + ((y+vy) - (float)r.a.y)*(float)(r.b.y-r.a.y))/(float)((r.a.x-r.b.x)*(r.a.x-r.b.x)+(r.a.y-r.b.y)*(r.a.y-r.b.y));
	float xint = (float)r.a.x + u*(float)(r.b.x-r.a.x);
	float yint = (float)r.a.y + u*(float)(r.b.y-r.a.y);
	float zint = (float)r.a.z + u*(float)(r.b.z-r.a.z);
	
	//make sure the intersection is along the rail
	if((((xint-0.4) > r.a.x) && ((xint-0.4) > r.b.x)) || (((xint+0.4) < r.a.x) && ((xint+0.4) < r.b.x))) return false;
	if((((yint-0.4) > r.a.y) && ((yint-0.4) > r.b.y)) || (((yint+0.4) < r.a.y) && ((yint+0.4) < r.b.y))) return false;
	if((((zint) > r.a.z) && ((zint) > r.b.z)) || (((zint+8) < r.a.z) && ((zint+8) < r.b.z))) return false;
	
	//collide with the rail?
	if((xint < (x+0.4+vx)) && (xint > (x-0.4+vx)) && (yint < (y+0.4+vy)) && (yint > (y-0.4+vy)) && (zint > (z+vz)) && (zint < (z+8+vz)))
	{
		//printf("i %d %.2f %.2f %.2f\n", i, xint,yint,zint);
		
		if(zint <= (z+3))
		{
			isgrindrail = true;
			isground = false;
			airtime = 10;
			walltime = 40;
			
			x = xint;
			y = yint;
			z = zint-0.1;
			
			float vec = (xint-r.a.x)*vx + (yint-r.a.y)*vy + (zint-r.a.z)*vz;
			if(vec > 0)
			{
				if(((xint-r.a.x) == 0) && ((yint-r.a.y) == 0) && ((zint-r.a.z) == 0)) return false;
				float mag = sqrt(vx*vx+vy*vy+vz*vz)/sqrt((xint-r.a.x)*(xint-r.a.x)+(yint-r.a.y)*(yint-r.a.y)+(zint-r.a.z)*(zint-r.a.z));
				vx = (xint-r.a.x)*mag;
				vy = (yint-r.a.y)*mag;
				vz = (zint-r.a.z)*mag;
			
				return true;
			}
			else
			{
				if(((xint-r.b.x) == 0) && ((yint-r.b.y) == 0) && ((zint-r.b.z) == 0)) return false;
				float mag = sqrt(vx*vx+vy*vy)/sqrt((xint-r.b.x)*(xint-r.b.x)+(yint-r.b.y)*(yint-r.b.y)+(zint-r.b.z)*(zint-r.b.z));
				vx = (xint-r.b.x)*mag;
				vy = (yint-r.b.y)*mag;
				vz = (zint-r.b.z)*mag;
				
				return true;
			}
		}
		else
		{
			//float mag = sqrt((x-xint)*(x-xint) + (y-yint)*(y-yint))
			
		}
	}
	//printf("i %.2f %.2f %.2f\n", xint,yint,zint);
	return false;
}

bool player::checkxcol()
{
	//There is a +5 -5 in this to make the truncations work correctly
	// -0.5 normally gets truncated to 0 but I'd like it to be truncated
	// to -1
	int xindexold = (int)(x+vx+5)-5;
	if(vx > 0)
	{
		waslastplusx = true;
		int xindexnew = (int)(x+0.4+vx+5)-5;
		
		if(xindexold != xindexnew)
		{
			//check base
			int b1,p1,b2,p2;
			gettileinfo(x+0.4+vx, y-0.4, &b1, &p1);
			gettileinfo(x+0.4+vx, y+0.4, &b2, &p2);
			
			if(b1 > (z+3))
			{
				vx = 0;
				x = (float)xindexnew-0.41;
				return true;
			}
			if(b2 > (z+3))
			{
				vx = 0;
				x = (float)xindexnew-0.41;
				return true;
			}
			
			//Check the platform
			if(p1 != 0)
			{
				if((p1 > (z+3)) && (p1 < (z+9)))
				{
					vx = 0;
					x = (float)xindexnew-0.41;
					return true;
				}
			}
			if(p2 != 0)
			{
				if((p2 > (z+3)) && (p2 < (z+9)))
				{
					vx = 0;
					x = (float)xindexnew-0.41;
					return true;
				}
			}
		}
		return false;
	}
	else if(vx < 0)
	{
		waslastplusx = false;
		int xindexnew = (int)(x-0.4+vx+5)-5;
		
		if(xindexold != xindexnew)
		{
			int b1,p1,b2,p2;
			gettileinfo(x-0.4+vx, y-0.4, &b1, &p1);
			gettileinfo(x-0.4+vx, y+0.4, &b2, &p2);
		
			//check base
			if(b1 > (z+3))
			{
				vx = 0;
				x = (float)xindexold+0.41;
				return true;
			}
			if(b2 > (z+3))
			{
				vx = 0;
				x = (float)xindexold+0.41;
				return true;
			}
			
			//Check the platform
			if(p1 != 0)
			{
				if((p1 > (z+3)) && (p1 < (z+9)))
				{
					vx = 0;
					x = (float)xindexold+0.41;
					return true;
				}
			}
			if(p2 != 0)
			{
				if((p2 > (z+3)) && (p2 < (z+9)))
				{
					vx = 0;
					x = (float)xindexold+0.41;
					return true;
				}
			}
		}
		return false;
	}
	return false;
}

bool player::checkycol()
{
	//There is a +5 -5 in this to make the truncations work correctly
	// -0.5 normally gets truncated to 0 but I'd like it to be truncated
	// to -1
	int yindexold = (int)(y+vy+5)-5;
	if(vy > 0)
	{
		waslastplusy = true;
		int yindexnew = (int)(y+0.4+vy+5)-5;
		
		if(yindexold != yindexnew)
		{
			//check base
			int b1,p1,b2,p2;
			gettileinfo(x-0.4, y+0.4+vy, &b1, &p1);
			gettileinfo(x+0.4, y+0.4+vy, &b2, &p2);
			
			if(b1 > (z+3))
			{
				vy = 0;
				y = (float)yindexnew-0.41;
				return true;
			}
			if(b2 > (z+3))
			{
				vy = 0;
				y = (float)yindexnew-0.41;
				return true;
			}
			
			//Check the platform
			if(p1 != 0)
			{
				if((p1 > (z+3)) && (p1 < (z+9)))
				{
					vy = 0;
					y = (float)yindexnew-0.41;
					return true;
				}
			}
			if(p2 != 0)
			{
				if((p2 > (z+3)) && (p2 < (z+9)))
				{
					vy = 0;
					y = (float)yindexnew-0.41;
					return true;
				}
			}
		}
		return false;
	}
	else if(vy < 0)
	{
		waslastplusy = false;
		int yindexnew = (int)(y-0.4+vy+5)-5;
		
		if(yindexold != yindexnew)
		{
			int b1,p1,b2,p2;
			gettileinfo(x-0.4, y-0.4+vy, &b1, &p1);
			gettileinfo(x+0.4, y-0.4+vy, &b2, &p2);
		
			//check base
			if(b1 > (z+3))
			{
				vy = 0;
				y = (float)yindexold+0.41;
				return true;
			}
			if(b2 > (z+3))
			{
				vy = 0;
				y = (float)yindexold+0.41;
				return true;
			}
			
			//Check the platform
			if(p1 != 0)
			{
				if((p1 > (z+3)) && (p1 < (z+9)))
				{
					vy = 0;
					y = (float)yindexold+0.41;
					return true;
				}
			}
			if(p2 != 0)
			{
				if((p2 > (z+3)) && (p2 < (z+9)))
				{
					vy = 0;
					y = (float)yindexold+0.41;
					return true;
				}
			}
		}
		return false;
	}
	return false;
}

bool player::handlez()
{

	//Gather up all the relevent tile heights
	// This looks like hell because it checks to see if the blocks 
	// around the current block are needed
	int bx1y1,bx1y2,bx2y1,bx2y2,px1y1,px1y2,px2y1,px2y2;
	
	gettileinfo(x-0.4, y-0.4, &bx1y1, &px1y1);
	gettileinfo(x+0.4, y-0.4, &bx2y1, &px2y1);
	gettileinfo(x-0.4, y+0.4, &bx1y2, &px1y2);
	gettileinfo(x+0.4, y+0.4, &bx2y2, &px2y2);
	
	//printf("\n %d %d %d %d", bx1y1,bx1y2,bx2y1,bx2y2);

	
	//Check if player landed
	if((int)z < bx1y1) {z = (float)bx1y1; isground = true; vz = 0; airtime = 10;}
	if((int)z < bx2y1) {z = (float)bx2y1; isground = true; vz = 0; airtime = 10;}
	if((int)z < bx1y2) {z = (float)bx1y2; isground = true; vz = 0; airtime = 10;}
	if((int)z < bx2y2) {z = (float)bx2y2; isground = true; vz = 0; airtime = 10;}
	
	if(((int)z < px1y1)&&((int)z >= (px1y1-3))) {z = (float)px1y1; isground = true; vz = 0; airtime = 10;}
	if(((int)z < px2y1)&&((int)z >= (px2y1-3))) {z = (float)px2y1; isground = true; vz = 0; airtime = 10;}
	if(((int)z < px1y2)&&((int)z >= (px1y2-3))) {z = (float)px1y2; isground = true; vz = 0; airtime = 10;}
	if(((int)z < px2y2)&&((int)z >= (px2y2-3))) {z = (float)px2y2; isground = true; vz = 0; airtime = 10;}
	
	if((isground == false) && (isgrindrail == false)) vz -= 0.04;
	
	if((isgrindwall == true) && (walltime > 0))
	{
		vz = 0;
		walltime--;
		
		if(vy == 0)
		{
			if(waslastplusy == false)
			{
				vy -= 0.3;
				if(checkycol() == false) isgrindwall = false;
				vy = 0;
			}
			else
			{
				vy += 0.3;
				if(checkycol() == false) isgrindwall = false;
				vy = 0;
			}
		}
		if(vx == 0)
		{
			if(waslastplusx == false)
			{
				vx -= 0.3;
				if(checkxcol() == false) isgrindwall = false;
				vx = 0;
			}
			else
			{
				vx += 0.3;
				if(checkxcol() == false) isgrindwall = false;
				vx = 0;
			}
		}
	}
	
	//Jump  (handels jumping off walls and eventually rails too)
	if ((keysDown() & KEY_A))
	{
		isjump = true;
		
		if((isgrindwall == true) && (walltime > 0) && (isground == false))
		{
			airtime = 10;
			if(vy == 0)
			{
				if(waslastplusy == false)
				{
					vy += 0.3;
				}
				else
				{
					vy -= 0.3;
				}
			}
			if(vx == 0)
			{
				if(waslastplusx == false)
				{
					vx += 0.3;
				}
				else
				{
					vx -= 0.3;
				}
			}
			walltime = 40;
			isgrindwall = false;
		}
	}
	if (((keysHeld() & KEY_A))&&(airtime > 0)&&(isjump == true))
	{
		if(airtime < 5) vz = 0.6;
		if(airtime > 5) vz = 0.4;
		isground = false;
		airtime--;
		if(airtime==0) isjump = false;
	}
	
	//See if player hits their head on the platform
	if(vz > 0)
	{
		float tmp = z+vz+8;
		if((tmp>px1y1)&&(z<px1y1)) vz = 0;
		if((tmp>px2y1)&&(z<px2y1)) vz = 0;
		if((tmp>px1y2)&&(z<px1y2)) vz = 0;
		if((tmp>px2y2)&&(z<px2y2)) vz = 0;
	}

	//Check if player walked off a ledge
	if(isground == true)
	{
		isgrindwall = false; //A few wallgrind variables are
		walltime = 40;			//Set here (if player is on the ground
		if(((int)z > px1y1)&&((int)z > px2y1)&&((int)z > px1y2)&&((int)z > px2y2)&&((int)z > bx1y1)&&((int)z > bx2y1)&&((int)z > bx1y2)&&((int)z > bx2y2))
		{
			isground = false;
			airtime = 0;
		}
	}
	
	return false;
}


void player::gettileinfo(float x, float y, int* b, int*p)
{
	int tempmapx,tempmapy,tempx,tempy;
	
	//printf("%d %d  ", (int)x, (int)y);
	if((int)x > 19)
	{
		tempmapx = mapx+1;
		tempx = 0;
	}
	else if(x < 0)
	{
		tempmapx = mapx-1;
		tempx = 19;
		//printf("\n x < 0");
	}
	else
	{
		tempmapx = mapx;
		tempx = (int)x;
	}
	
	if((int)y > 19)
	{
		tempmapy = mapy+1;
		tempy = 0;
		//printf("\n y > 19");
	}
	else if(y < 0)
	{
		tempmapy = mapy-1;
		tempy = 19;
		//printf("\n y < 0");
	}
	else
	{
		tempmapy = mapy;
		tempy = (int)y;
	}
	
	*b = m->getblockbase(tempmapx,tempmapy,tempx,tempy);
	*p = m->getblockplat(tempmapx,tempmapy,tempx,tempy);
	return;
}

void player::setplayercam()
{
	float camdist = sqrt((camx-x)*(camx-x) + (camy-y)*(camy-y));
	
	if(camdist > maxcamdist)
	{
		float ratio = maxcamdist/camdist;
		camx = (camx-x)*ratio + x;
		camy = (camy-y)*ratio + y;
	}
	
	if(camdist < mincamdist)
	{
		float ratio = mincamdist/camdist;
		camx = (camx-x)*ratio + x;
		camy = (camy-y)*ratio + y;
	}
	
	camz = z+7;

	glLoadIdentity();
	gluLookAt(  camx/10, camy/10, camz/40,	//camera possition 
				x/10, y/10, (z+4)/40,				//look at
				0.0, 0.0, 1.0);				//up
}

void player::setframe()
{
	animation++;
	/*if(isground==true)
	{
	}*/
	if((vx==0)&&(vy==0)&&(vz==0))
	{
		if(animation>74) animation = 0;
		frame = animation/2;
		return;
	}
	//if(player is in slow skate mode)
		if(animation<37) animation = 38;
		if(animation>99) animation = 38;
		frame = animation;
		return;
	
}
	
void player::drawplayer()
{	
	if(ModelEnable == true)
	{
	//glEnable(GL_OUTLINE);
	//glSetOutlineColor (0, RGB15(0, 0, 0));
	
	//glPolyFmt(POLY_ALPHA(31) | POLY_CULL_FRONT | POLY_ID(0));
	
		glPushMatrix();
		glTranslatef(x/10,y/10,z/40);
		//glRotatef(dir,0.0f,0.0f,1.0f);
		glRotatef(dir+90,0.0f,0.0f,1.0f); // add 90 to make the player face forward
		//glScalef(12,12,12); // temporary scale because I suck at modelling
	
		glBindTexture (GL_TEXTURE_2D, Texture[0]);
		glColorTable(GL_RGB256, TexturePal[0]);		
		RenderMD2Model(frame,Model,ModelEnable);
	
		glPopMatrix(1);
	
	//glDisable(GL_OUTLINE);
	}
}

void player::drawplayercolmap()
{
	glPolyFmt(POLY_ALPHA(0) | POLY_CULL_NONE);

	glPushMatrix();
	glTranslatef(x/10,y/10,z/40);
	
	glColor3f(1.0f,0.0f,0.0f);
	
	glBegin(GL_QUADS);
		glVertex3f(0.04,0.04,0.0);	//Bottom
		glVertex3f(-0.04,0.04,0.0);
		glVertex3f(-0.04,-0.04,0.0);
		glVertex3f(0.04,-0.04,0.0);
	
		glVertex3f(0.04,0.04,0.16);	//Top
		glVertex3f(-0.04,0.04,0.16);
		glVertex3f(-0.04,-0.04,0.16);
		glVertex3f(0.04,-0.04,0.16);
	
		glVertex3f(0.04,0.04,0.0);	//Side1
		glVertex3f(0.04,0.04,0.16);
		glVertex3f(0.04,-0.04,0.16);
		glVertex3f(0.04,-0.04,0.0);
	
		glVertex3f(-0.04,0.04,0.0);	//Side2
		glVertex3f(-0.04,0.04,0.16);
		glVertex3f(-0.04,-0.04,0.16);
		glVertex3f(-0.04,-0.04,0.0);
	
		glVertex3f(0.04,0.04,0.0);	//Side3
		glVertex3f(0.04,0.04,0.16);
		glVertex3f(-0.04,0.04,0.16);
		glVertex3f(-0.04,0.04,0.0);
	
		glVertex3f(0.04,-0.04,0.0);	//Side4
		glVertex3f(0.04,-0.04,0.16);
		glVertex3f(-0.04,-0.04,0.16);
		glVertex3f(-0.04,-0.04,0.0);
	glEnd();
	
	glColor3f(0.0f,0.0f,1.0f);
	
	glRotatef(dir,0.0f,0.0f,1.0f);
	
	glBegin(GL_TRIANGLE_STRIP);
		glVertex3f( 0.03, 0.03, 0.08);
		glVertex3f( 0.08, 0.00, 0.08);
		glVertex3f( 0.03, 0.00, 0.12);
		glVertex3f( 0.03, -0.03, 0.08);
		glVertex3f( 0.03, 0.03, 0.08);
	glEnd();
	
	glPopMatrix(1);
	
	glColor3f(1.0f,1.0f,1.0f);
	
	glPolyFmt(POLY_ALPHA(31) | POLY_CULL_FRONT);
}


